
// <copyright file="RecordExecutionFlowHelper.cs" company="Subhadra Software Solutions">
//   
// </copyright>
// <summary>
//   The record execution flow helper.
// </summary>

namespace SubhadraSolutions.Sharp.Utils.Diagnostics.Performance
{
    using System;
    using System.Collections.Generic;

    using SubhadraSolutions.Sharp.Utils.Collections.Generic;
    using SubhadraSolutions.Sharp.Utils.Diagnostics.Performance.Internal;
    using SubhadraSolutions.Sharp.Utils.Reflection;

    /// <summary>
    /// The record execution flow helper.
    /// </summary>
    public static class RecordExecutionFlowHelper
    {
        #region Static Fields

        /// <summary>
        /// The container.
        /// </summary>
        [ThreadStatic]
        private static ExecutionFlowContainer _container;

        #endregion Static Fields

        #region Public Properties

        /// <summary>
        /// Gets the thread object name.
        /// </summary>
        public static string ThreadObjectName
        {
            get
            {
                return "EXECUTION_FLOW";
            }
        }

        #endregion Public Properties

        #region Public Methods and Operators

        /// <summary>
        /// </summary>
        /// <param name="className">
        /// </param>
        /// <param name="methodName">
        /// </param>
        /// <param name="arguments">
        /// </param>
        /// <returns>
        /// The <see cref="ExecutionFlow"/>.
        /// </returns>
        /// <remarks>
        /// [CAUTION]. [CALLED BY REFLECTION]
        /// </remarks>
        [CautionUsedByReflectionAttribute]
        public static ExecutionFlow MethodCalled(string className, string methodName, IList<Pair<string, object>> arguments)
        {
            bool isNew;
            ExecutionFlow flow = getFlow(className, methodName, arguments, out isNew);
            if (!isNew)
            {
                flow.MethodCalled(className, methodName, arguments);
            }

            return flow;
        }

        /// <summary>
        /// </summary>
        /// <param name="flow">
        /// </param>
        /// <param name="ex">
        /// </param>
        /// <remarks>
        /// [CAUTION]. [CALLED BY REFLECTION]
        /// </remarks>
        [CautionUsedByReflectionAttribute]
        public static void MethodExecuted(ExecutionFlow flow, Exception ex)
        {
            flow.MethodExecuted(ex);
            if (flow.IsExecutionCompleted)
            {
                // Thread.FreeNamedDataSlot(ThreadObjectName);
                _container.flow = null;
                ExecutionFlowRecorder.Instance.RaiseFlowRecordedEvent(flow);
            }
        }

        #endregion Public Methods and Operators

        #region Methods

        /// <summary>
        /// The get flow.
        /// </summary>
        /// <param name="className">
        /// The class name.
        /// </param>
        /// <param name="methodName">
        /// The method name.
        /// </param>
        /// <param name="arguments">
        /// The arguments.
        /// </param>
        /// <param name="isNew">
        /// The is new.
        /// </param>
        /// <returns>
        /// The <see cref="ExecutionFlow"/>.
        /// </returns>
        private static ExecutionFlow getFlow(string className, string methodName, IList<Pair<string, object>> arguments, out bool isNew)
        {
            isNew = false;
            if (_container == null)
            {
                _container = new ExecutionFlowContainer();
            }

            if (_container.flow == null)
            {
                isNew = true;
                _container.flow = new ExecutionFlow(className, methodName, arguments);
            }

            // LocalDataStoreSlot slot = Thread.GetNamedDataSlot(ThreadObjectName);
            // ExecutionFlow flow = Thread.GetData(slot) as ExecutionFlow;
            // if (flow == null)
            // {
            // flow = new ExecutionFlow(className, methodName, arguments);
            // Thread.SetData(slot, flow);
            // isNew = true;
            // }
            return _container.flow;
        }

        #endregion Methods

        // private static ConcurrentDictionary<string, ExecutionFlow> _flows = new ConcurrentDictionary<string, ExecutionFlow>();
        // public static string ThreadObjectName
        // {
        // get { return "EXECUTION_FLOW"; }
        // }
        // public static ExecutionFlow MethodCalled(string className, string methodName, IList<Pair<string, object>> arguments)
        // {
        // bool isNew = false;
        // ExecutionFlow flow = getFlow(className, methodName, arguments, out isNew);
        // if (!isNew)
        // {
        // flow.MethodCalled(className, methodName, arguments);
        // }
        // return flow;
        // }
        // public static void MethodExecuted(ExecutionFlow flow, Exception ex)
        // {
        // flow.MethodExecuted(ex);
        // if (flow.IsExecutionCompleted)
        // {
        // ExecutionFlow f = null;
        // _flows.TryRemove(flow.Name.ExportAsString(), out f);
        // Thread.FreeNamedDataSlot(ThreadObjectName);
        // ExecutionFlowRecorder.Instance.RaiseFlowRecordedEvent(flow);
        // }
        // }
        // private static ExecutionFlow getFlow(string className, string methodName, IList<Pair<string, object>> arguments, out bool isNew)
        // {
        // isNew = false;
        // LocalDataStoreSlot slot = Thread.GetNamedDataSlot(ThreadObjectName);
        // if (slot == null)
        // {
        // slot = Thread.AllocateNamedDataSlot(ThreadObjectName);
        // }
        // ExecutionFlow flow = null;
        // string id = Thread.GetData(slot) as string;
        // if (id == null)
        // {
        // flow = new ExecutionFlow(className, methodName, arguments);
        // id = flow.Name.ExportAsString();
        // _flows.TryAdd(id, flow);
        // Thread.SetData(slot, id);
        // isNew = true;
        // }
        // else
        // {
        // _flows.TryGetValue(id, out flow);
        // }
        // return flow;
        // }
    }
}